<!DOCTYPE html>
<html style="display: none;" lang="zh">
    <head>
    <!-- hexo-inject:begin --><!-- hexo-inject:end --><meta charset="utf-8">
    <!--
        © Material Theme
        https://github.com/viosey/hexo-theme-material
        Version: 1.5.6 -->
    <script>
        window.materialVersion = "1.5.6"
        // Delete localstorage with these tags
        window.oldVersion = [
            'codestartv1',
            '1.3.4',
            '1.4.0',
            '1.4.0b1',
            '1.5.0',
            '1.5.2',
            '1.5.5'
        ]
    </script>

    <!-- dns prefetch -->
    <meta http-equiv="x-dns-prefetch-control" content="on">





    <link rel="dns-prefetch" href="https://xuefeng.disqus.com"/>



    <link rel="dns-prefetch" href="https://www.google-analytics.com"/>



    <link rel="dns-prefetch" href="https://fonts.googleapis.com"/>





    <!-- Meta & Info -->
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta name="renderer" content="webkit">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">

    <!-- Title -->
    
    <title>
        
            记百度前端一面 | 
        
        boXue·Fengke
    </title>

    <!-- Favicons -->
    <link rel="icon shortcut" type="image/ico" href="/img/kcalb_logo_nobg.png">
    <link rel="icon" href="/img/kcalb_logo_nobg.png">

    <meta name="format-detection" content="telephone=no"/>
    <meta name="description" itemprop="description" content="">
    <meta name="keywords" content=",Javascript">
    <meta name="theme-color" content="#0097A7">

    <!-- Disable Fucking Bloody Baidu Tranformation -->
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />

    <!--[if lte IE 9]>
        <link rel="stylesheet" href="/css/ie-blocker.css">

        
            <script src="/js/ie-blocker.zhCN.js"></script>
        
    <![endif]-->

    <!-- Import lsloader -->
    <script>(function(){window.lsloader={jsRunSequence:[],jsnamemap:{},cssnamemap:{}};lsloader.removeLS=function(a){try{localStorage.removeItem(a)}catch(b){}};lsloader.setLS=function(a,c){try{localStorage.setItem(a,c)}catch(b){}};lsloader.getLS=function(a){var c="";try{c=localStorage.getItem(a)}catch(b){c=""}return c};versionString="/*"+(window.materialVersion||"unknownVersion")+"*/";lsloader.clean=function(){try{var b=[];for(var a=0;a<localStorage.length;a++){b.push(localStorage.key(a))}b.forEach(function(e){var f=lsloader.getLS(e);if(window.oldVersion){var d=window.oldVersion.reduce(function(g,h){return g||f.indexOf("/*"+h+"*/")!==-1},false);if(d){lsloader.removeLS(e)}}})}catch(c){}};lsloader.clean();lsloader.load=function(f,a,b,d){if(typeof b==="boolean"){d=b;b=undefined}d=d||false;b=b||function(){};var e;e=this.getLS(f);if(e&&e.indexOf(versionString)===-1){this.removeLS(f);this.requestResource(f,a,b,d);return}if(e){var c=e.split(versionString)[0];if(c!=a){console.log("reload:"+a);this.removeLS(f);this.requestResource(f,a,b,d);return}e=e.split(versionString)[1];if(d){this.jsRunSequence.push({name:f,code:e});this.runjs(a,f,e)}else{document.getElementById(f).appendChild(document.createTextNode(e));b()}}else{this.requestResource(f,a,b,d)}};lsloader.requestResource=function(b,e,a,c){var d=this;if(c){this.iojs(e,b,function(h,f,g){d.setLS(f,h+versionString+g);d.runjs(h,f,g)})}else{this.iocss(e,b,function(f){document.getElementById(b).appendChild(document.createTextNode(f));d.setLS(b,e+versionString+f)},a)}};lsloader.iojs=function(d,b,g){var a=this;a.jsRunSequence.push({name:b,code:""});try{var f=new XMLHttpRequest();f.open("get",d,true);f.onreadystatechange=function(){if(f.readyState==4){if((f.status>=200&&f.status<300)||f.status==304){if(f.response!=""){g(d,b,f.response);return}}a.jsfallback(d,b)}};f.send(null)}catch(c){a.jsfallback(d,b)}};lsloader.iocss=function(f,c,h,a){var b=this;try{var g=new XMLHttpRequest();g.open("get",f,true);g.onreadystatechange=function(){if(g.readyState==4){if((g.status>=200&&g.status<300)||g.status==304){if(g.response!=""){h(g.response);a();return}}b.cssfallback(f,c,a)}};g.send(null)}catch(d){b.cssfallback(f,c,a)}};lsloader.iofonts=function(f,c,h,a){var b=this;try{var g=new XMLHttpRequest();g.open("get",f,true);g.onreadystatechange=function(){if(g.readyState==4){if((g.status>=200&&g.status<300)||g.status==304){if(g.response!=""){h(g.response);a();return}}b.cssfallback(f,c,a)}};g.send(null)}catch(d){b.cssfallback(f,c,a)}};lsloader.runjs=function(f,c,e){if(!!c&&!!e){for(var b in this.jsRunSequence){if(this.jsRunSequence[b].name==c){this.jsRunSequence[b].code=e}}}if(!!this.jsRunSequence[0]&&!!this.jsRunSequence[0].code&&this.jsRunSequence[0].status!="failed"){var a=document.createElement("script");a.appendChild(document.createTextNode(this.jsRunSequence[0].code));a.type="text/javascript";document.getElementsByTagName("head")[0].appendChild(a);this.jsRunSequence.shift();if(this.jsRunSequence.length>0){this.runjs()}}else{if(!!this.jsRunSequence[0]&&this.jsRunSequence[0].status=="failed"){var d=this;var a=document.createElement("script");a.src=this.jsRunSequence[0].path;a.type="text/javascript";this.jsRunSequence[0].status="loading";a.onload=function(){d.jsRunSequence.shift();if(d.jsRunSequence.length>0){d.runjs()}};document.body.appendChild(a)}}};lsloader.tagLoad=function(b,a){this.jsRunSequence.push({name:a,code:"",path:b,status:"failed"});this.runjs()};lsloader.jsfallback=function(c,b){if(!!this.jsnamemap[b]){return}else{this.jsnamemap[b]=b}for(var a in this.jsRunSequence){if(this.jsRunSequence[a].name==b){this.jsRunSequence[a].code="";this.jsRunSequence[a].status="failed";this.jsRunSequence[a].path=c}}this.runjs()};lsloader.cssfallback=function(e,c,b){if(!!this.cssnamemap[c]){return}else{this.cssnamemap[c]=1}var d=document.createElement("link");d.type="text/css";d.href=e;d.rel="stylesheet";d.onload=d.onerror=b;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(d,a)};lsloader.runInlineScript=function(c,b){var a=document.getElementById(b).innerText;this.jsRunSequence.push({name:c,code:a});this.runjs()}})();</script>

    <!-- Import queue -->
    <script>function Queue(){this.dataStore=[];this.offer=b;this.poll=d;this.execNext=a;this.debug=false;this.startDebug=c;function b(e){if(this.debug){console.log("Offered a Queued Function.")}if(typeof e==="function"){this.dataStore.push(e)}else{console.log("You must offer a function.")}}function d(){if(this.debug){console.log("Polled a Queued Function.")}return this.dataStore.shift()}function a(){var e=this.poll();if(e!==undefined){if(this.debug){console.log("Run a Queued Function.")}e()}}function c(){this.debug=true}}var queue=new Queue();</script>

    <!-- Import CSS -->
    
        <style id="material_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("material_css","/css/material.min.css?Z7a72R1E4SxzBKR/WGctOA==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
        <style id="style_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("style_css","/css/style.min.css?NKhlKQkXw/c66TR5p4wO+w==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>

        

    

    

    <!-- Config CSS -->

<!-- Other Styles -->
<style>
  body, html {
    font-family: Roboto, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
    overflow-x: hidden !important;
  }
  
  code {
    font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
  }

  a {
    color: #00838F;
  }

  .mdl-card__media,
  #search-label,
  #search-form-label:after,
  #scheme-Paradox .hot_tags-count,
  #scheme-Paradox .sidebar_archives-count,
  #scheme-Paradox .sidebar-colored .sidebar-header,
  #scheme-Paradox .sidebar-colored .sidebar-badge{
    background-color: #0097A7 !important;
  }

  /* Sidebar User Drop Down Menu Text Color */
  #scheme-Paradox .sidebar-colored .sidebar-nav>.dropdown>.dropdown-menu>li>a:hover,
  #scheme-Paradox .sidebar-colored .sidebar-nav>.dropdown>.dropdown-menu>li>a:focus {
    color: #0097A7 !important;
  }

  #post_entry-right-info,
  .sidebar-colored .sidebar-nav li:hover > a,
  .sidebar-colored .sidebar-nav li:hover > a i,
  .sidebar-colored .sidebar-nav li > a:hover,
  .sidebar-colored .sidebar-nav li > a:hover i,
  .sidebar-colored .sidebar-nav li > a:focus i,
  .sidebar-colored .sidebar-nav > .open > a,
  .sidebar-colored .sidebar-nav > .open > a:hover,
  .sidebar-colored .sidebar-nav > .open > a:focus,
  #ds-reset #ds-ctx .ds-ctx-entry .ds-ctx-head a {
    color: #0097A7 !important;
  }

  .toTop {
    background: #757575 !important;
  }

  .material-layout .material-post>.material-nav,
  .material-layout .material-index>.material-nav,
  .material-nav a {
    color: #757575;
  }

  #scheme-Paradox .MD-burger-layer {
    background-color: #757575;
  }

  #scheme-Paradox #post-toc-trigger-btn {
    color: #757575;
  }

  .post-toc a:hover {
    color: #00838F;
    text-decoration: underline;
  }

</style>


<!-- Theme Background Related-->

    <style>
      body{
        background-color: #F5F5F5;
      }

      /* blog_info bottom background */
      #scheme-Paradox .material-layout .something-else .mdl-card__supporting-text{
        background-color: #fff;
      }
    </style>




<!-- Fade Effect -->

    <style>
      .fade {
        transition: all 800ms linear;
        -webkit-transform: translate3d(0,0,0);
        -moz-transform: translate3d(0,0,0);
        -ms-transform: translate3d(0,0,0);
        -o-transform: translate3d(0,0,0);
        transform: translate3d(0,0,0);
        opacity: 1;
      }

      .fade.out{
        opacity: 0;
      }
    </style>


<!-- Import Font -->
<!-- Import Roboto -->

    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">


<!-- Import Material Icons -->


    <style id="material_icons"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("material_icons","/css/material-icons.css?pqhB/Rd/ab0H2+kZp0RDmw==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>




    <!-- Import jQuery -->
    
        <script>lsloader.load("jq_js","/js/jquery.min.js?qcusAULNeBksqffqUM2+Ig==", true)</script>
    

    <!-- WebAPP Icons -->
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="application-name" content="boXue·Fengke">
    <meta name="msapplication-starturl" content="https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html">
    <meta name="msapplication-navbutton-color" content="#0097A7">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-title" content="boXue·Fengke">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon" href="/img/kcalb_logo_nobg.png">

    <!-- Site Verification -->
    <meta name="google-site-verification" content="google0da443a51f3ca324" />
    

    <!-- RSS -->
    

    <!-- The Open Graph protocol -->
    <meta property="og:url" content="https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html">
    <meta property="og:type" content="blog">
    <meta property="og:title" content="记百度前端一面 | boXue·Fengke">
    <meta property="og:image" content="/img/kcalb_logo_nobg.png">
    <meta property="og:description" content="">
    <meta property="og:article:tag" content="Javascript"> 

    
        <meta property="article:published_time" content="Tue Aug 06 2019 14:22:00 GMT+0000">
        <meta property="article:modified_time" content="Sat May 23 2020 05:22:21 GMT+0000">
    

    <!-- The Twitter Card protocol -->
    <meta name="twitter:card" content="summary_large_image">

    <!-- Add canonical link for SEO -->
    
        <link rel="canonical" href="https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html" />
    

    <!-- Structured-data for SEO -->
    
        


<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "mainEntityOfPage": "https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html",
    "headline": "记百度前端一面",
    "datePublished": "Tue Aug 06 2019 14:22:00 GMT+0000",
    "dateModified": "Sat May 23 2020 05:22:21 GMT+0000",
    "author": {
        "@type": "Person",
        "name": "w-xuefeng",
        "image": {
            "@type": "ImageObject",
            "url": "https://pub.wangxuefeng.com.cn/asset/defaultHead/avatar.png"
        },
        "description": "不念过往 不畏将来"
    },
    "publisher": {
        "@type": "Organization",
        "name": "boXue·Fengke",
        "logo": {
            "@type":"ImageObject",
            "url": "/img/kcalb_logo_nobg.png"
        }
    },
    "keywords": ",Javascript",
    "description": "",
}
</script>


    

    <!-- Analytics -->
    
        <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
    ga('create', 'UA-109928914-1', 'auto');ga('send', 'pageview');
</script>
    
    
    

    <!-- Custom Head -->
    

<meta name="generator" content="Hexo 4.2.1"><link rel="stylesheet" href="/css/prism-ghcolors.css" type="text/css"><!-- hexo-inject:begin --><!-- hexo-inject:end --></head>


    
        <body id="scheme-Paradox" class="lazy">
            <!-- hexo-inject:begin --><!-- hexo-inject:end --><div class="material-layout  mdl-js-layout has-drawer is-upgraded">
                

                <!-- Main Container -->
                <main class="material-layout__content" id="main">

                    <!-- Top Anchor -->
                    <div id="top"></div>

                    
                        <!-- Hamburger Button -->
                        <button class="MD-burger-icon sidebar-toggle">
                            <span id="MD-burger-id" class="MD-burger-layer"></span>
                        </button>
                    

                    <!-- Post TOC -->

    
    <!-- Back Button -->
    <!--
    <div class="material-back" id="backhome-div" tabindex="0">
        <a class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
           href="#" onclick="window.history.back();return false;"
           target="_self"
           role="button"
           data-upgraded=",MaterialButton,MaterialRipple">
            <i class="material-icons" role="presentation">arrow_back</i>
            <span class="mdl-button__ripple-container">
                <span class="mdl-ripple"></span>
            </span>
        </a>
    </div>
    -->


    <!-- Left aligned menu below button -->
    
    




<!-- Layouts -->

    <!-- Post Module -->
    <div class="material-post_container">

        <div class="material-post mdl-grid">
            <div class="mdl-card mdl-shadow--4dp mdl-cell mdl-cell--12-col">

                <!-- Post Header(Thumbnail & Title) -->
                
    <!-- Paradox Post Header -->
    
        <!-- Custom Thumbnail -->
        <div class="post_thumbnail-custom mdl-card__media mdl-color-text--grey-50" style="background-image:url(https://pub.wangxuefeng.com.cn/asset/blogthumbnail/baiduInterview/thumbnail.png)">
    
            <p class="article-headline-p">
                记百度前端一面
            </p>
        </div>





                
                    <!-- Paradox Post Info -->
                    <div class="mdl-color-text--grey-700 mdl-card__supporting-text meta">

    <!-- Author Avatar -->
    <div id="author-avatar">
        <img src="https://pub.wangxuefeng.com.cn/asset/defaultHead/avatar.png" width="44px" height="44px" alt="Author Avatar"/>
    </div>
    <!-- Author Name & Date -->
    <div>
        <strong>w-xuefeng</strong>
        <span>8月 06, 2019</span>
    </div>

    <div class="section-spacer"></div>

    <!-- Favorite -->
    <!--
        <button id="article-functions-like-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon btn-like">
            <i class="material-icons" role="presentation">favorite</i>
            <span class="visuallyhidden">favorites</span>
        </button>
    -->

    <!-- Qrcode -->
    
        <button id="article-functions-qrcode-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
    <i class="material-icons" role="presentation">devices other</i>
    <span class="visuallyhidden">devices other</span>
</button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-functions-qrcode-button">
    <li class="mdl-menu__item">在其它设备中阅读本文章</li>
    
        <img src="">
    
</ul>

    

    <!-- Tags (bookmark) -->
    
    <button id="article-functions-viewtags-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
        <i class="material-icons" role="presentation">bookmark</i>
        <span class="visuallyhidden">bookmark</span>
    </button>
    <ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-functions-viewtags-button">
        <li class="mdl-menu__item">
        <a class="post_tag-link" href="/tags/Javascript/" rel="tag">Javascript</a>
    </ul>
    

    <!-- Share -->
    
        <button id="article-fuctions-share-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
    <i class="material-icons" role="presentation">share</i>
    <span class="visuallyhidden">share</span>
</button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-fuctions-share-button">
    

    

    <!-- Share Weibo -->
    
        <a class="post_share-link" href="http://service.weibo.com/share/share.php?appkey=&title=记百度前端一面&url=https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html&pic=https://blog.wangxuefeng.com.cn/img/kcalb_logo_nobg.png&searchPic=false&style=simple" target="_blank">
            <li class="mdl-menu__item">
                分享到微博
            </li>
        </a>
    

    <!-- Share Twitter -->
    
        <a class="post_share-link" href="https://twitter.com/intent/tweet?text=记百度前端一面&url=https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html&via=w-xuefeng" target="_blank">
            <li class="mdl-menu__item">
                分享到 Twitter
            </li>
        </a>
    

    <!-- Share Facebook -->
    
        <a class="post_share-link" href="https://www.facebook.com/sharer/sharer.php?u=https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html" target="_blank">
            <li class="mdl-menu__item">
                分享到 Facebook
            </li>
        </a>
    

    <!-- Share Google+ -->
    
        <a class="post_share-link" href="https://plus.google.com/share?url=https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html" target="_blank">
            <li class="mdl-menu__item">
                分享到 Google+
            </li>
        </a>
    

    <!-- Share LinkedIn -->
    

    <!-- Share QQ -->
    
        <a class="post_share-link" href="http://connect.qq.com/widget/shareqq/index.html?site=boXue·Fengke&title=记百度前端一面&summary=&pics=https://blog.wangxuefeng.com.cn/img/kcalb_logo_nobg.png&url=https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html" target="_blank">
            <li class="mdl-menu__item">
                分享到 QQ
            </li>
        </a>
    

    <!-- Share Telegram -->
    
</ul>

    
</div>

                

                <!-- Post Content -->
                <div id="post-content" class="mdl-color-text--grey-700 mdl-card__supporting-text fade out">
    
        <p>2019年7月31日，这天烈日当空，骄阳似火，我孤身前往北京百度科技园，参加百度前端社招面试。</p>
<p>谜之自信的我，从不做面试前的准备，刷面试题对我来说是不可能的，顶多也就瞟两眼，不会花很多时间在这个上面，更愿意把时间都用来真正实践中项目中。然鹅我还是<code>Too young Too naive</code>🤦‍！</p>
<p>到了北京百度科技园，进入K2大厅，首先映入眼帘的是大厅中央的AI机器人，然后就是百度的Logo，环视一周，感觉不愧是百度在北京的总部，K2的大厅要比网易在北京研发中心的大厅大一点。距离约定好的面试时间还有一点时间，我被安排在右边的沙发上等待面试官。就在此时，我拿起我的荣耀手机，随手拍了一张大厅的照片。如下</p>
<div style="width:100%;display:flex;flex-direction:column;justify-content:center;text-align:center;">

  <img src="https://pub.wangxuefeng.com.cn/asset/blogthumbnail/baiduInterview/hall.jpg" style="width:100%;max-width:600px;margin: 5px auto;">

</div>

<p>到了约定的时间，面试官带我通过门禁，进入<code>后堂</code>，前往面试的小桌边。扫视一周，发现周围全都是面试或者讨论问题的人，我，只是这芸芸众生中的一员。</p>
<p>接下来开始正式面试了，面试官手拿Mac，上面有我的电子简历，开始询问问题，我也开始回答问题。</p>
<p>还是那句话，我真的是<code>Too young Too naive</code>，面试官问的问题都是能百度到的面试题，而我就是没有去刷。虽然一些问题大概是知道的，但是原理性的东西东很模糊，回答起来都很笼统，可越是笼统的回答，面试官就越是要详细的去问，这个时候，就只能乖乖的回答<em>I don’t Know</em>了，倘若稍加要蒙混过关，那么就是诚信问题了。经过这样<code>宁静而又祥和的</code>面试后，面试结果也就心知肚明了。归根到底，还是自己基础不扎实，没有追根溯源，搞明白原理。所以学习一定要有探索精神，要探究本源，弄清原理，不能糊弄自己，要对的起自己付出的时间。</p>
<p>好了，废话不多说，直接上题吧：</p>
<ul>
<li><p>1.你在上一家公司实习用的什么前端框架？</p>
<blockquote>
<p>Angular</p>
</blockquote>
</li>
<li><p>2.你认为 Angular 和 Vue 各自的优缺点在什么地方？</p>
<blockquote>
<p>Angular，出生比 Vue 早，相对 Vue 要更加”老练”, 适合做大型 Web 项目。Angular 采用“脏值检测”的方式，数据发生变更后，对于所有的数据和视图的绑定关系进行一次检测，识别是否有数据发生了改变，有变化进行处理，可能进一步引发其他数据的改变，所以这个过程可能会循环几次，一直到不再有数据变化发生后，将变更的数据发送到视图，更新页面展现。</p>
</blockquote>
<blockquote>
<p>Vue，定位用于中小型前端项目，相对于 Angular 更加年轻。Vue 使用 Object.defineProperty() 方法，监控对数据的操作，从而可以自动触发数据同步。并且，由于是在不同的数据上触发同步，可以精确的将变更发送给绑定的视图，而不是对所有的数据都执行一次检测。</p>
</blockquote>
</li>
<li><p>3.那你说说 Angular 的 “脏值检测” 吧，会不会有性能问题？</p>
<blockquote>
<p>Angular 团队通过对 <a href="https://github.com/angular/angular/tree/master/packages/zone.js" target="_blank" rel="noopener">zone.js</a> 封装，实现了 脏检查机制（Change Detection 或 Dirty Checking）。<br>Angular 默认是脏检查方法是从根组件开始，遍历所有的子组件进行脏检查。</p>
<p>触发条件</p>
<ul>
<li>Ajax 请求， </li>
<li>Timeout 延迟事件，</li>
<li>鼠标事件</li>
</ul>
<p>触发脏检测的目的就是检测视图(DOM)有没有发生变化，方法就是比较 双向绑定中 view 和 model 是否一致。</p>
<p>脏检测的效率必然不会太高，但也不会很慢。性能优化的话，可以从</p>
<ul>
<li>减少逻辑代码的复杂程度</li>
<li>减少 Event Handler（可做节流和防抖）</li>
<li>降低 DOM 树复杂度<br>等几方面进行。</li>
</ul>
<p>具体可参考文章</p>
<ul>
<li><a href="https://www.jianshu.com/p/850f0f76e908" target="_blank" rel="noopener">如何理解angular的脏检查</a></li>
<li><a href="https://blog.csdn.net/wf19930209/article/details/83515873" target="_blank" rel="noopener">Angular性能优化之脏检测</a></li>
</ul>
</blockquote>
</li>
<li><p>4.为什么说 Vue 定位于中小型前端项目，有什么例子能证明 Vue 不能做或者做不好大型项目吗？</p>
<blockquote>
<p>Vue.js 官网这样介绍自己：<br>Vue (读音 /vjuː/，类似于 view) 是一套用于构建用户界面的渐进式框架。<strong>与其它大型框架不同的是，Vue 被设计为可以自底向上逐层应用</strong>。</p>
<p>具体有什么例子能证明 Vue 不能做或者做不好大型项目暂时还不太清楚，但是能确定的是 Vue 生而为“简”。与 React 的简单对比如下图所示：</p>
</blockquote>
<div style="width:100%;display:flex;flex-direction:column;justify-content:center;text-align:center;">

  <img src="https://pub.wangxuefeng.com.cn/asset/blogthumbnail/baiduInterview/vue&react1.png" style="width:100%;max-width:500px;margin: 5px auto;">

  <img src="https://pub.wangxuefeng.com.cn/asset/blogthumbnail/baiduInterview/vue&react2.png" style="width:100%;max-width:500px;margin: 5px auto;">

  <p>（图片来自<a href="https://www.jianshu.com/p/b7cd52868e95" target="_blank">vue和react的区别之我见</a>）</p>

</div>

<blockquote>
<p>具体可参考</p>
<ul>
<li><a href="https://baijiahao.baidu.com/s?id=1608099200125495014&wfr=spider&for=pc" target="_blank" rel="noopener">React.js与Vue.js：流行框架的比较</a></li>
<li><a href="https://www.jianshu.com/p/b7cd52868e95" target="_blank" rel="noopener">vue和react的区别之我见</a></li>
</ul>
</blockquote>
</li>
<li><p>5.说说 Vue 的双向绑定原理吧。</p>
<blockquote>
<p>Vue.js 官网解释如下：</p>
<p>当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项，Vue 将遍历此对象所有的属性，并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性，这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。</p>
<p>这些 getter/setter 对用户来说是不可见的，但是在内部它们让 Vue 能够追踪依赖，在属性被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同，所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。</p>
<p>每个组件实例都对应一个 watcher 实例，它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时，会通知 watcher，从而使它关联的组件重新渲染。</p>
</blockquote>
<div style="width:100%;display:flex;flex-direction:column;justify-content:center;text-align:center;">

  <img src="https://pub.wangxuefeng.com.cn/asset/blogthumbnail/baiduInterview/vue.png" style="width:100%;max-width:500px;margin: 5px auto;">

  <p>（图片来自<a href="https://cn.vuejs.org/v2/guide/reactivity.html" target="_blank">Vue.js 官网 深入响应式原理</a>）</p>

</div>


</li>
</ul>
<blockquote>
<p>自己的理解：Vue 通过 Object.defineProperty() 将传入参数的 data 的属性全部转为 getter/setter。在getter/setter 的内部实现对数据监控和拦截，并结合发布者-订阅者模式，在数据变动时发布消息给订阅者，触发相应的监听回调，并更新视图。</p>
</blockquote>
<ul>
<li><p>6.能说说Object.defineProperty()这个方法吗，还有在 Vue 的双向绑定原理中 getter/setter 里面具体做了什么？ </p>
<blockquote>
<p>Object.defineProperty(obj, prop, descriptor)</p>
<p>接收三个参数，分别是</p>
<ul>
<li>obj 要在其上定义属性的对象</li>
<li>prop 要定义或修改的属性的名称</li>
<li>descriptor 将被定义或修改的属性描述符</li>
</ul>
<p>返回 被传递给函数的对象</p>
<p>关于 <code>descriptor</code>, 称为属性描述符，对象里目前存在的属性描述符有两种主要形式：<strong>数据描述符</strong>和<strong>存取描述符</strong>。<br><br><strong>数据描述符</strong>是一个具有值的属性，该值可能是可写的，也可能不是可写的。<br><br><strong>存取描述符</strong>是由 getter-setter 函数对描述的属性。<br><br><strong>描述符必须是这两种形式之一；不能同时是两者</strong>。</p>
<p>数据描述符和存取描述符均具有以下可选键值</p>
<p>(默认值是在使用Object.defineProperty()定义属性的情况下)：</p>
<ul>
<li>configurable 当且仅当该属性的 configurable 为 true 时，该属性描述符才能够被改变，同时该属性也能从对应的对象上被删除。<code>默认为 false</code>。</li>
<li>enumerable 当且仅当该属性的enumerable为true时，该属性才能够出现在对象的枚举属性中。<code>默认为 false</code>。</li>
</ul>
<p>数据描述符同时具有以下可选键值：</p>
<ul>
<li>value 该属性对应的值。可以是任何有效的 JavaScript 值（数值，对象，函数等）。<code>默认为 undefined</code>。</li>
<li>writable 当且仅当该属性的writable为true时，value才能被赋值运算符改变。<code>默认为 false</code>。  </li>
</ul>
<p>存取描述符同时具有以下可选键值：</p>
<ul>
<li>get 一个给属性提供 getter 的方法，如果没有 getter 则为 undefined。当访问该属性时，该方法会被执行，方法执行时没有参数传入，但是会传入this对象（由于继承关系，这里的this并不一定是定义该属性的对象）。<code>默认为 undefined</code>。</li>
<li>set 一个给属性提供 setter 的方法，如果没有 setter 则为 undefined。当属性值修改时，触发执行该方法。该方法将接受唯一参数，即该属性新的参数值。<code>默认为 undefined</code>。</li>
</ul>
<p><strong>如果一个描述符不具有value,writable,get 和 set 任意一个关键字，那么它将被认为是一个数据描述符。如果一个描述符同时有(value或writable)和(get或set)关键字，将会产生一个异常</strong>。</p>
<p>如果同时要定义或修改多个属性，可以使用 <code>Object.defineProperties(obj, props)</code><br>如：</p>
</blockquote>
<pre class=" language-js"><code class="language-js">    <span class="token keyword">var</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    Object<span class="token punctuation">.</span><span class="token function">defineProperties</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token punctuation">{</span>
      <span class="token string">'property1'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        value<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
        writable<span class="token punctuation">:</span> <span class="token boolean">true</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token string">'property2'</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
        value<span class="token punctuation">:</span> <span class="token string">'Hello'</span><span class="token punctuation">,</span>
        writable<span class="token punctuation">:</span> <span class="token boolean">false</span>
      <span class="token punctuation">}</span>
      <span class="token comment" spellcheck="true">// etc. etc.</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<blockquote>
<p>Vue 的双向绑定原理中 getter/setter 里面具体做了什么，看看源码：</p>
<p>源码来自：<a href="https://github.com/vuejs/vue/blob/dev/src/core/observer/index.js" target="_blank" rel="noopener">https://github.com/vuejs/vue/blob/dev/src/core/observer/index.js</a></p>
</blockquote>
<pre class=" language-js"><code class="language-js">
  <span class="token comment" spellcheck="true">// ...</span>
  <span class="token comment" spellcheck="true">/**
  * Define a reactive property on an Object.
  */</span>
  <span class="token keyword">export</span> <span class="token keyword">function</span> defineReactive <span class="token punctuation">(</span>
    obj<span class="token punctuation">:</span> Object<span class="token punctuation">,</span>
    key<span class="token punctuation">:</span> string<span class="token punctuation">,</span>
    val<span class="token punctuation">:</span> any<span class="token punctuation">,</span>
    customSetter<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token operator">?</span>Function<span class="token punctuation">,</span>
    shallow<span class="token operator">?</span><span class="token punctuation">:</span> boolean
  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> dep <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dep</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">const</span> property <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertyDescriptor</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> key<span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>property <span class="token operator">&amp;&amp;</span> property<span class="token punctuation">.</span>configurable <span class="token operator">===</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span>
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">// cater for pre-defined getter/setters</span>
    <span class="token keyword">const</span> getter <span class="token operator">=</span> property <span class="token operator">&amp;&amp;</span> property<span class="token punctuation">.</span><span class="token keyword">get</span>
    <span class="token keyword">const</span> setter <span class="token operator">=</span> property <span class="token operator">&amp;&amp;</span> property<span class="token punctuation">.</span><span class="token keyword">set</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token operator">!</span>getter <span class="token operator">||</span> setter<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> arguments<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      val <span class="token operator">=</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">let</span> childOb <span class="token operator">=</span> <span class="token operator">!</span>shallow <span class="token operator">&amp;&amp;</span> <span class="token function">observe</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span>
    Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> key<span class="token punctuation">,</span> <span class="token punctuation">{</span>
      enumerable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      configurable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      <span class="token keyword">get</span><span class="token punctuation">:</span> <span class="token keyword">function</span> reactiveGetter <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> value <span class="token operator">=</span> getter <span class="token operator">?</span> getter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">:</span> val
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>childOb<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            childOb<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token function">dependArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> value
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token keyword">set</span><span class="token punctuation">:</span> <span class="token keyword">function</span> reactiveSetter <span class="token punctuation">(</span>newVal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> value <span class="token operator">=</span> getter <span class="token operator">?</span> getter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">:</span> val
        <span class="token comment" spellcheck="true">/* eslint-disable no-self-compare */</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>newVal <span class="token operator">===</span> value <span class="token operator">||</span> <span class="token punctuation">(</span>newVal <span class="token operator">!==</span> newVal <span class="token operator">&amp;&amp;</span> value <span class="token operator">!==</span> value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">return</span>
        <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">/* eslint-enable no-self-compare */</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>NODE_ENV <span class="token operator">!==</span> <span class="token string">'production'</span> <span class="token operator">&amp;&amp;</span> customSetter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">customSetter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">// #7981: for accessor properties without setter</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>getter <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>setter<span class="token punctuation">)</span> <span class="token keyword">return</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>setter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          setter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> newVal<span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          val <span class="token operator">=</span> newVal
        <span class="token punctuation">}</span>
        childOb <span class="token operator">=</span> <span class="token operator">!</span>shallow <span class="token operator">&amp;&amp;</span> <span class="token function">observe</span><span class="token punctuation">(</span>newVal<span class="token punctuation">)</span>
        dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token comment" spellcheck="true">/**
  * Collect dependencies on array elements when the array is touched, since
  * we cannot intercept array element access like property getters.
  */</span>
  <span class="token keyword">function</span> dependArray <span class="token punctuation">(</span>value<span class="token punctuation">:</span> Array<span class="token operator">&lt;</span>any<span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> e<span class="token punctuation">,</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> l <span class="token operator">=</span> value<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> l<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      e <span class="token operator">=</span> value<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
      e <span class="token operator">&amp;&amp;</span> e<span class="token punctuation">.</span>__ob__ <span class="token operator">&amp;&amp;</span> e<span class="token punctuation">.</span>__ob__<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">dependArray</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment" spellcheck="true">// ...</span>
</code></pre>
<blockquote>
<p>其中 get </p>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token keyword">get</span><span class="token punctuation">:</span> <span class="token keyword">function</span> reactiveGetter <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> value <span class="token operator">=</span> getter <span class="token operator">?</span> getter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">:</span> val
    <span class="token comment" spellcheck="true">// 判断 property 是否已经具有 getter</span>
    <span class="token comment" spellcheck="true">// 如果已经具有 getter，则调用该 getter</span>
    <span class="token comment" spellcheck="true">// 否则 value 为该属性值</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// Dep 为一个订阅器，判断是否需要添加订阅者，也可以叫做收集依赖</span>
      dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token comment" spellcheck="true">// 添加订阅者 收集依赖</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>childOb<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 如果需要添加子订阅者</span>
        childOb<span class="token punctuation">.</span>dep<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true">// childOb.dep 为一个子订阅器，在子订阅器添加订阅者</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment" spellcheck="true">// 如果 value 是数组的话</span>
          <span class="token function">dependArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
          <span class="token comment" spellcheck="true">// （递归）添加数组订阅者，监听数组的变化</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> value
    <span class="token comment" spellcheck="true">// 返回 value</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<blockquote>
<p>set</p>
</blockquote>
<pre class=" language-js"><code class="language-js"><span class="token keyword">set</span><span class="token punctuation">:</span> <span class="token keyword">function</span> reactiveSetter <span class="token punctuation">(</span>newVal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> value <span class="token operator">=</span> getter <span class="token operator">?</span> getter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">:</span> val
  <span class="token comment" spellcheck="true">// 获取修改前的 value</span>

  <span class="token comment" spellcheck="true">/* eslint-disable no-self-compare */</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>newVal <span class="token operator">===</span> value <span class="token operator">||</span> <span class="token punctuation">(</span>newVal <span class="token operator">!==</span> newVal <span class="token operator">&amp;&amp;</span> value <span class="token operator">!==</span> value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment" spellcheck="true">// 如果 新的值与修改前相同 直接返回</span>
    <span class="token keyword">return</span>
  <span class="token punctuation">}</span>
  <span class="token comment" spellcheck="true">/* eslint-enable no-self-compare */</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span>NODE_ENV <span class="token operator">!==</span> <span class="token string">'production'</span> <span class="token operator">&amp;&amp;</span> customSetter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment" spellcheck="true">// 如果在生产环境下并且具有 customSetter， 则调用 customSetter</span>
    <span class="token function">customSetter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token comment" spellcheck="true">// #7981: for accessor properties without setter</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>getter <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>setter<span class="token punctuation">)</span> <span class="token keyword">return</span>
  <span class="token comment" spellcheck="true">// 如果没有 setter 访问者属性的话直接返回</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>setter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment" spellcheck="true">// 如果 property 已经有 setter，调用 setter</span>
    setter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> newVal<span class="token punctuation">)</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  <span class="token comment" spellcheck="true">// 否则 进行赋值</span>
    val <span class="token operator">=</span> newVal
  <span class="token punctuation">}</span>
  childOb <span class="token operator">=</span> <span class="token operator">!</span>shallow <span class="token operator">&amp;&amp;</span> <span class="token function">observe</span><span class="token punctuation">(</span>newVal<span class="token punctuation">)</span>
  <span class="token comment" spellcheck="true">// （递归）更新子订阅器</span>
  dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token comment" spellcheck="true">// 向订阅者发布更新，更新视图</span>
<span class="token punctuation">}</span></code></pre>
<blockquote>
<p>源码传送门</p>
<ul>
<li><a href="https://github.com/vuejs/vue/blob/dev/src/core/observer/index.js" target="_blank" rel="noopener">双向绑定具体实现 源码</a></li>
<li><a href="https://github.com/vuejs/vue/blob/dev/src/core/observer/watcher.js" target="_blank" rel="noopener">Watcher 的具体实现 源码</a></li>
<li><a href="https://github.com/vuejs/vue/blob/dev/src/core/observer/dep.js" target="_blank" rel="noopener">Dep 的具体实现 源码</a></li>
</ul>
<p>简单总结一下就是，在 getter 中添加订阅，收集依赖， 在 setter 中发布订阅，更新依赖和视图</p>
</blockquote>
</li>
<li><p>7.说说 Vue 中 watch 和 computed 的区别。</p>
<blockquote>
<ul>
<li><p><a href="https://cn.vuejs.org/v2/guide/computed.html" target="_blank" rel="noopener">vue 官网的解释</a></p>
</li>
<li><p>简单总结一下：</p>
<ul>
<li>computed: 计算属性，用于复杂的逻辑计算，并且基于它们的响应式依赖将计算结果进行缓存以减少性能开销，如果不希望有缓存，可以使用方法来替代。计算属性默认只有 getter ，不过在需要时也可以提供一个 setter。计算属性不可在 data 里面定义, 。</li>
<li>watch: 侦听器, 用于在数据变化时需要执行异步或开销较大的操作时，每个 watch 具有 oldValue 和 newValue 参数；可以设置中间状态，这些都是计算属性无法做到的。</li>
</ul>
</li>
<li><p>具体实现 computed:</p>
</li>
</ul>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token comment" spellcheck="true">// src/core/instance/state.js</span>

  <span class="token comment" spellcheck="true">// 初始化计算属性</span>
  <span class="token keyword">function</span> initComputed <span class="token punctuation">(</span>vm<span class="token punctuation">:</span> Component<span class="token punctuation">,</span> computed<span class="token punctuation">:</span> Object<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>
    <span class="token comment" spellcheck="true">// 遍历 computed 计算属性</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> key <span class="token keyword">in</span> computed<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token operator">...</span>
      <span class="token comment" spellcheck="true">// 创建 Watcher 实例</span>
      <span class="token comment" spellcheck="true">// create internal watcher for the computed property.</span>
      watchers<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> getter <span class="token operator">||</span> noop<span class="token punctuation">,</span> noop<span class="token punctuation">,</span> computedWatcherOptions<span class="token punctuation">)</span>

      <span class="token comment" spellcheck="true">// 创建属性 并将提供的函数将用作属性的 getter，</span>
      <span class="token comment" spellcheck="true">// 最终 computed 与 data 会一起混合到 vm 下，所以当 computed 与 data 存在重名属性时会抛出警告</span>
      <span class="token function">defineComputed</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> key<span class="token punctuation">,</span> userDef<span class="token punctuation">)</span>
      <span class="token operator">...</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">export</span> <span class="token keyword">function</span> defineComputed <span class="token punctuation">(</span>target<span class="token punctuation">:</span> any<span class="token punctuation">,</span> key<span class="token punctuation">:</span> string<span class="token punctuation">,</span> userDef<span class="token punctuation">:</span> Object <span class="token operator">|</span> Function<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>
    <span class="token comment" spellcheck="true">// 创建 get set 方法</span>
    sharedPropertyDefinition<span class="token punctuation">.</span><span class="token keyword">get</span> <span class="token operator">=</span> <span class="token function">createComputedGetter</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span>
    sharedPropertyDefinition<span class="token punctuation">.</span><span class="token keyword">set</span> <span class="token operator">=</span> noop
    <span class="token operator">...</span>
    <span class="token comment" spellcheck="true">// 创建属性，并初始化 getter setter</span>
    Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> sharedPropertyDefinition<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> createComputedGetter <span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">function</span> computedGetter <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> watcher <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_computedWatchers <span class="token operator">&amp;&amp;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_computedWatchers<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>watcher<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>watcher<span class="token punctuation">.</span>dirty<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment" spellcheck="true">// watcher 暴露 evaluate 方法用于取值操作</span>
          watcher<span class="token punctuation">.</span><span class="token function">evaluate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">// 判断是否处于依赖收集状态</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          watcher<span class="token punctuation">.</span><span class="token function">depend</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> watcher<span class="token punctuation">.</span>value
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<p>无论是属性还是计算属性，都会生成一个对应的 watcher 实例。</p>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token comment" spellcheck="true">// src/core/observer/watcher.js</span>

  <span class="token comment" spellcheck="true">// 当获取计算属性时，就会进到这个 getter 方法</span>
  <span class="token keyword">get</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// this 指的是 watcher 实例</span>
    <span class="token comment" spellcheck="true">// 将当前 watcher 实例暂存到 Dep.target，这就表示开启了依赖收集任务</span>
    <span class="token function">pushTarget</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
    <span class="token keyword">let</span> value
    <span class="token keyword">const</span> vm <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>vm
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// 在执行定义计算属性的函数时，会触发属性和计算属性的 getter</span>
      <span class="token comment" spellcheck="true">// 在这个执行过程中，就可以收集到定义计算属性的依赖了</span>
      value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>getter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> vm<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">handleError</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> vm<span class="token punctuation">,</span> <span class="token template-string"><span class="token string">`getter for watcher "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>expression<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"`</span></span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> e
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>deep<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">traverse</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      <span class="token comment" spellcheck="true">// 结束依赖收集任务</span>
      <span class="token function">popTarget</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">cleanupDeps</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> value
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<p>dep</p>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token comment" spellcheck="true">// src/core/observer/dep.js</span>

  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token class-name">Dep</span> <span class="token punctuation">{</span>
    <span class="token keyword">static</span> target<span class="token punctuation">:</span> <span class="token operator">?</span>Watcher<span class="token punctuation">;</span>
    id<span class="token punctuation">:</span> number<span class="token punctuation">;</span>
    subs<span class="token punctuation">:</span> Array<span class="token operator">&lt;</span>Watcher<span class="token operator">></span><span class="token punctuation">;</span>

    constructor <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> uid<span class="token operator">++</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>subs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>

    addSub <span class="token punctuation">(</span>sub<span class="token punctuation">:</span> Watcher<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>subs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>sub<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    removeSub <span class="token punctuation">(</span>sub<span class="token punctuation">:</span> Watcher<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">remove</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>subs<span class="token punctuation">,</span> sub<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    depend <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        Dep<span class="token punctuation">.</span>target<span class="token punctuation">.</span><span class="token function">addDep</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    notify <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> subs <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>subs<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> l <span class="token operator">=</span> subs<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i <span class="token operator">&lt;</span> l<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 更新 watcher 的值，与 watcher.evaluate() 类似，</span>
        <span class="token comment" spellcheck="true">// 但 update 是给依赖变化时使用的，包含对 watch 的处理</span>
        subs<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment" spellcheck="true">// 当首次计算 computed 属性的值时，Dep 将会在计算期间对依赖进行收集</span>
  Dep<span class="token punctuation">.</span>target <span class="token operator">=</span> <span class="token keyword">null</span>
  <span class="token keyword">const</span> targetStack <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>

  <span class="token keyword">export</span> <span class="token keyword">function</span> pushTarget <span class="token punctuation">(</span>_target<span class="token punctuation">:</span> Watcher<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// 在一次依赖收集期间，如果有其他依赖收集任务开始（比如：当前 computed 计算属性嵌套其他 computed 计算属性），</span>
    <span class="token comment" spellcheck="true">// 那么将会把当前 target 暂存到 targetStack，先进行其他 target 的依赖收集，</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span> targetStack<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span>
    Dep<span class="token punctuation">.</span>target <span class="token operator">=</span> _target
  <span class="token punctuation">}</span>

  <span class="token keyword">export</span> <span class="token keyword">function</span> popTarget <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// 当嵌套的依赖收集任务完成后，将 target 恢复为上一层的 Watcher，并继续做依赖收集</span>
    Dep<span class="token punctuation">.</span>target <span class="token operator">=</span> targetStack<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>    </code></pre>
<blockquote>
<p>总结一下依赖收集、动态计算的流程：</p>
<ul>
<li><p>data 属性初始化 getter setter</p>
</li>
<li><p>computed 计算属性初始化，提供的函数将用作属性的 getter</p>
</li>
<li><p>当首次获取计算属性的值时，Dep 开始依赖收集</p>
</li>
<li><p>在执行 getter 方法时，如果 Dep 处于依赖收集状态，则判定 该属性为 计算属性 的依赖，并建立依赖关系</p>
</li>
<li><p>当 所依赖的属性 发生变化时，根据依赖关系，触发 计算属性的函数 重新计算</p>
<p>参考文章：<a href="https://segmentfault.com/a/1190000010408657" target="_blank" rel="noopener">深入理解 Vue Computed 计算属性</a></p>
</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>具体实现 watch:</li>
</ul>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token comment" spellcheck="true">// 初始化</span>
  <span class="token comment" spellcheck="true">// initState -> initWatch</span>

  <span class="token keyword">function</span> <span class="token function">Vue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token operator">...</span> <span class="token comment" spellcheck="true">// 其他处理</span>
    <span class="token function">initState</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
    <span class="token operator">...</span> <span class="token comment" spellcheck="true">// 解析模板，生成DOM 插入页面</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">function</span> initState <span class="token punctuation">(</span>vm<span class="token punctuation">:</span> Component<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span> <span class="token comment" spellcheck="true">// 处理 data，props，computed 等数据</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>opts<span class="token punctuation">.</span>watch <span class="token operator">&amp;&amp;</span> opts<span class="token punctuation">.</span>watch <span class="token operator">!==</span> nativeWatch<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">initWatch</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> opts<span class="token punctuation">.</span>watch<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">function</span> initWatch <span class="token punctuation">(</span>vm<span class="token punctuation">:</span> Component<span class="token punctuation">,</span> watch<span class="token punctuation">:</span> Object<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> key <span class="token keyword">in</span> watch<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> handler <span class="token operator">=</span> watch<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> handler<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">createWatcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> key<span class="token punctuation">,</span> handler<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">createWatcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> key<span class="token punctuation">,</span> handler<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment" spellcheck="true">/**
  * Strict object type check. Only returns true
  * for plain JavaScript objects.
  */</span>
  <span class="token keyword">function</span> isPlainObject <span class="token punctuation">(</span>obj<span class="token punctuation">:</span> any<span class="token punctuation">)</span><span class="token punctuation">:</span> boolean <span class="token punctuation">{</span>
    <span class="token keyword">return</span> _toString<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'[object Object]'</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">function</span> createWatcher <span class="token punctuation">(</span>
    vm<span class="token punctuation">:</span> Component<span class="token punctuation">,</span>
    expOrFn<span class="token punctuation">:</span> string <span class="token operator">|</span> Function<span class="token punctuation">,</span>
    handler<span class="token punctuation">:</span> any<span class="token punctuation">,</span>
    options<span class="token operator">?</span><span class="token punctuation">:</span> Object
  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// expOrFn 是 key，handler 可能是对象</span>

    <span class="token comment" spellcheck="true">// 监听属性的值是一个对象，包含handler，deep，immediate</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPlainObject</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      options <span class="token operator">=</span> handler
      handler <span class="token operator">=</span> handler<span class="token punctuation">.</span>handler
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> handler <span class="token operator">===</span> <span class="token string">'string'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      handler <span class="token operator">=</span> vm<span class="token punctuation">[</span>handler<span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> vm<span class="token punctuation">.</span><span class="token function">$watch</span><span class="token punctuation">(</span>expOrFn<span class="token punctuation">,</span> handler<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  Vue<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>$watch <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span>
      expOrFn<span class="token punctuation">:</span> string <span class="token operator">|</span> Function<span class="token punctuation">,</span>
      cb<span class="token punctuation">:</span> any<span class="token punctuation">,</span>
      options<span class="token operator">?</span><span class="token punctuation">:</span> Object
    <span class="token punctuation">)</span><span class="token punctuation">:</span> Function <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// expOrFn 是 监听的 key，cb 是监听的回调，options 是 监听的所有选项</span>
      <span class="token keyword">const</span> vm<span class="token punctuation">:</span> Component <span class="token operator">=</span> <span class="token keyword">this</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isPlainObject</span><span class="token punctuation">(</span>cb<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">createWatcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> expOrFn<span class="token punctuation">,</span> cb<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      options <span class="token operator">=</span> options <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
      options<span class="token punctuation">.</span>user <span class="token operator">=</span> <span class="token boolean">true</span>
      <span class="token keyword">const</span> watcher <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> expOrFn<span class="token punctuation">,</span> cb<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>immediate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 设定了立即执行，马上执行回调</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
          cb<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> watcher<span class="token punctuation">.</span>value<span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">handleError</span><span class="token punctuation">(</span>error<span class="token punctuation">,</span> vm<span class="token punctuation">,</span> <span class="token template-string"><span class="token string">`callback for immediate watcher "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>watcher<span class="token punctuation">.</span>expression<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"`</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> <span class="token keyword">function</span> unwatchFn <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        watcher<span class="token punctuation">.</span><span class="token function">teardown</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">class</span> <span class="token class-name">Watcher</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// ...</span>
    constructor <span class="token punctuation">(</span>
      vm<span class="token punctuation">:</span> Component<span class="token punctuation">,</span>
      expOrFn<span class="token punctuation">:</span> string <span class="token operator">|</span> Function<span class="token punctuation">,</span>
      cb<span class="token punctuation">:</span> Function<span class="token punctuation">,</span>
      options<span class="token operator">?</span><span class="token punctuation">:</span> <span class="token operator">?</span>Object<span class="token punctuation">,</span>
      isRenderWatcher<span class="token operator">?</span><span class="token punctuation">:</span> boolean
    <span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// ...</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>vm <span class="token operator">=</span> vm
      <span class="token keyword">this</span><span class="token punctuation">.</span>deep <span class="token operator">=</span> opt<span class="token punctuation">.</span>deep
      <span class="token keyword">this</span><span class="token punctuation">.</span>cb <span class="token operator">=</span> cb
      <span class="token comment" spellcheck="true">// ...</span>
      <span class="token comment" spellcheck="true">// parse expression for getter</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> expOrFn <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>getter <span class="token operator">=</span> expOrFn
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>getter <span class="token operator">=</span> <span class="token function">parsePath</span><span class="token punctuation">(</span>expOrFn<span class="token punctuation">)</span>
        <span class="token comment" spellcheck="true">// ...</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>lazy
          <span class="token operator">?</span> undefined
          <span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span>            
        <span class="token comment" spellcheck="true">// this.get 作用就是执行 this.getter 函数</span>
    <span class="token punctuation">}</span>
    <span class="token comment" spellcheck="true">// ...</span>
    <span class="token keyword">get</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// this 指的是 watcher 实例</span>
      <span class="token comment" spellcheck="true">// 将当前 watcher 实例暂存到 Dep.target，这就表示开启了依赖收集任务</span>
      <span class="token function">pushTarget</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
      <span class="token keyword">let</span> value
      <span class="token keyword">const</span> vm <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>vm
      <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 触发 getter</span>
        value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>getter<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> vm<span class="token punctuation">)</span>
      <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token function">handleError</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> vm<span class="token punctuation">,</span> <span class="token template-string"><span class="token string">`getter for watcher "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>expression<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"`</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token keyword">throw</span> e
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>deep<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment" spellcheck="true">// 处理深度监听</span>
          <span class="token function">traverse</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">// 结束依赖收集任务</span>
        <span class="token function">popTarget</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">cleanupDeps</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> value
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">/**
    * Subscriber interface.
    * Will be called when a dependency changes.
    */</span>
    update <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">/* istanbul ignore else */</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>lazy<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>dirty <span class="token operator">=</span> <span class="token boolean">true</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>sync<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token function">queueWatcher</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">/**
    * Scheduler job interface.
    * Will be called by the scheduler.
    */</span>
    run <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>active<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>
          value <span class="token operator">!==</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">||</span>
          <span class="token comment" spellcheck="true">// Deep watchers and watchers on Object/Arrays should fire even</span>
          <span class="token comment" spellcheck="true">// when the value is the same, because the value may</span>
          <span class="token comment" spellcheck="true">// have mutated.</span>
          <span class="token function">isObject</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">||</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span>deep
        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment" spellcheck="true">// set new value</span>
          <span class="token keyword">const</span> oldValue <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value
          <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value
          <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment" spellcheck="true">// cb 是监听回调</span>
            <span class="token keyword">try</span> <span class="token punctuation">{</span>
              <span class="token keyword">this</span><span class="token punctuation">.</span>cb<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">,</span> value<span class="token punctuation">,</span> oldValue<span class="token punctuation">)</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token function">handleError</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">,</span> <span class="token template-string"><span class="token string">`callback for watcher "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>expression<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"`</span></span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>cb<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">,</span> value<span class="token punctuation">,</span> oldValue<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token comment" spellcheck="true">// ...</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> seenObjects <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token comment" spellcheck="true">/**
  * Recursively traverse an object to evoke all converted
  * getters, so that every nested property inside the object
  * is collected as a "deep" dependency.
  * 递归遍历一个对象以唤起所有转换的 getter，使对象内的每个嵌套属性被收集为“深层”依赖
  */</span>

  <span class="token keyword">export</span> <span class="token keyword">function</span> traverse <span class="token punctuation">(</span>val<span class="token punctuation">:</span> any<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">_traverse</span><span class="token punctuation">(</span>val<span class="token punctuation">,</span> seenObjects<span class="token punctuation">)</span>
    seenObjects<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> _traverse <span class="token punctuation">(</span>val<span class="token punctuation">:</span> any<span class="token punctuation">,</span> seen<span class="token punctuation">:</span> SimpleSet<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> i<span class="token punctuation">,</span> keys
    <span class="token keyword">const</span> isA <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token operator">!</span>isA <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token function">isObject</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">||</span> Object<span class="token punctuation">.</span><span class="token function">isFrozen</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span> <span class="token operator">||</span> val <span class="token keyword">instanceof</span> <span class="token class-name">VNode</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>val<span class="token punctuation">.</span>__ob__<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> depId <span class="token operator">=</span> val<span class="token punctuation">.</span>__ob__<span class="token punctuation">.</span>dep<span class="token punctuation">.</span>id
      <span class="token keyword">if</span> <span class="token punctuation">(</span>seen<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>depId<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span>
      <span class="token punctuation">}</span>
      seen<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>depId<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">// 不断递归深入读取对象，收集依赖</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>isA<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// val[i] 就是读取值了，然后值的对象就能收集到 watch-watcher</span>
      i <span class="token operator">=</span> val<span class="token punctuation">.</span>length
      <span class="token keyword">while</span> <span class="token punctuation">(</span>i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token function">_traverse</span><span class="token punctuation">(</span>val<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> seen<span class="token punctuation">)</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      keys <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span>
      i <span class="token operator">=</span> keys<span class="token punctuation">.</span>length
      <span class="token keyword">while</span> <span class="token punctuation">(</span>i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token function">_traverse</span><span class="token punctuation">(</span>val<span class="token punctuation">[</span>keys<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">,</span> seen<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
</code></pre>
<blockquote>
<p>大概总结一下</p>
<ul>
<li>1.获取监听回调<ul>
<li>如果配置是个对象，就取 handler 字段</li>
<li>如果配置是函数，那么直接就是 监听回调</li>
<li>如果配置是字符串，从实例上获取函数</li>
</ul>
</li>
<li>2.调用 vm.$watch<ul>
<li>判断是否立即执行监听回调</li>
<li>每个 watch 配发 watcher</li>
<li>watcher 在结尾会立即执行一次 watcher.get，其中便会执行 getter，便会根据监听的 key，去实例上读取并返回，存放在 watcher.value 上</li>
<li>通过 traverse 实现深度监听</li>
<li>通过 watcher.update 实现更新，并调用 监听回调且传入新值和旧值</li>
</ul>
</li>
</ul>
<p>参考文章：<a href="https://segmentfault.com/a/1190000019684439" target="_blank" rel="noopener">【Vue原理】Watch - 源码版</a></p>
</blockquote>
</li>
<li><p>8.谈谈 XSS 和 CSRF 的区别。</p>
<blockquote>
<p>XSS (Cross Site Scripting)，即跨站脚本攻击，是一种常见于 Web 应用中的计算机安全漏洞。<br>恶意攻击者往 Web 页面里嵌入恶意的客户端脚本，当用户浏览此网页时，脚本就会在用户的浏览器上执行，进而达到攻击者的目的。<br>比如获取用户的 Cookie、导航到恶意网站、携带木马等。借助安全圈里面非常有名的一句话：</p>
</blockquote>
<pre><code>  所有的输入都是有害的。</code></pre><blockquote>
<p>CSRF（Cross-site request forgery）跨站请求伪造，也被称为“One Click Attack”或者Session Riding，通常缩写为CSRF或者XSRF，是一种对网站的恶意利用。尽管听起来像跨站脚本（XSS），但它与XSS非常不同，XSS利用站点内的信任用户，而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比，CSRF攻击往往不大流行（因此对其进行防范的资源也相当稀少）和难以防范，所以被认为比XSS更具危险性。</p>
</blockquote>
<blockquote>
<p>详见</p>
<ul>
<li><a href="https://blog.csdn.net/weixin_39327883/article/details/89512217" target="_blank" rel="noopener">简述XSS和CSRF的概念和区别</a></li>
<li><a href="https://blog.csdn.net/zl834205311/article/details/81773511" target="_blank" rel="noopener">XSS及CSRF攻击防御</a></li>
</ul>
</blockquote>
</li>
<li><p>9.解决跨域的方式有哪些？</p>
<blockquote>
<ul>
<li>1.jsonp</li>
<li>2.PostMessage, PostMessage 是一个用于安全地使用跨源通信的方法。它允许来自不同源的脚本采用异步的方式进行有限的通信，可以实现跨文本档、多窗口、跨域消息传递，相当于提供了一个受控的机制来安全地绕过浏览器的同源限制</li>
<li>3.CORS，服务端设置 <code>header( &quot;Access-Control-Allow-Origin:*&quot; );</code></li>
<li>4.代理, 开发环境下可以配置 webpack 的 devServer 下的 proxy，生产环境中可以通过配置nginx或apache等服务端程序代理转发请求</li>
</ul>
</blockquote>
</li>
<li><p>10.说说前端页面的性能优化吧。</p>
<blockquote>
<ul>
<li>1.尽量减少 HTTP 请求个数</li>
<li>2.使用 CDN（内容分发网络）</li>
<li>3.为文件头指定 Expires 或 Cache-Control ，使内容具有缓存性。</li>
<li>4.避免空的 src 和 href</li>
<li>5.使用 gzip 压缩内容</li>
<li>6.把 CSS 放到顶部</li>
<li>7.把 JS 放到底部</li>
<li>8.避免使用 CSS 表达式</li>
<li>9.将 CSS 和 JS 放到外部文件中</li>
<li>10.减少 DNS 查找次数</li>
<li>11.精简 CSS 和 JS</li>
<li>12.减少页面重定向</li>
<li>13.剔除重复的 JS 和 CSS</li>
<li>14.配置 ETags</li>
<li>15.使 AJAX 可缓存</li>
<li>16.尽早刷新输出缓冲</li>
<li>17.使用 GET 来完成 AJAX 请求</li>
<li>18.延迟加载</li>
<li>19.预加载</li>
<li>20.减少 DOM 元素个数</li>
<li>21.根据域名划分页面内容</li>
<li>22.尽量减少 iframe 的个数</li>
<li>23.避免 404</li>
<li>24.减少 Cookie 的大小</li>
<li>25.使用无 cookie 的域</li>
<li>26.减少 DOM 访问</li>
<li>27.用 <code>&lt;link&gt;</code> 代替 <code>@import</code></li>
<li>28.避免使用滤镜</li>
<li>29.优化图像</li>
<li>30.优化 CSS Spirite</li>
<li>31.favicon.ico要小而且可缓存</li>
<li>32.保持单个内容小于25K、</li>
<li>等等</li>
</ul>
</blockquote>
</li>
<li><p>11 具体说说<code>预加载</code>和<code>延迟加载</code>。</p>
<blockquote>
<ul>
<li><p><strong>预加载</strong>: 预加载是一种浏览器机制，使用浏览器空闲时间来预先下载/加载用户接下来很可能会浏览的页面/资源，当用户访问某个预加载的链接时，如果从缓存命中,页面就得以快速呈现</p>
</li>
<li><p><strong>延迟加载</strong>：通过对<code>script</code>标签设置<code>defer</code> 或 <code>async</code>属性实现异步加载。</p>
</li>
<li><p>async 与 defer 的异同：</p>
<ul>
<li>相同点：异步加载文件</li>
<li>不同点：<ul>
<li>async：虽然是异步加载，但当有多个脚本异步加载的时候，不一定先加载哪一个，加载顺序不一定</li>
<li>defer：加载顺序由第一个延迟脚本到最后一个延迟脚本</li>
<li>Chrome下的真实情况见<a href="https://segmentfault.com/a/1190000006778717" target="_blank" rel="noopener">浅谈script标签的defer和async</a>,<pre><code>所以，通俗来讲，chrome 浏览器首先会请求HTML文档，然后对其中的各种资源调用相应的资源加载器进行异步网络请求，同时进行DOM渲染，直到遇到 &lt;script&gt; 标签的时候，主进程才会停止渲染等待此资源加载完毕然后调用V8引擎对js解析，继而继续进行 DOM 解析。
我的理解如果加了async 属性就相当于单独开了一个进程去独立加载和执行，而 defer 是和将 &lt;script&gt; 放到 &lt;body&gt; 底部一样的效果。  </code></pre></li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
</li>
<li><p>12.了解<strong>防抖</strong>和<strong>节流</strong>吗？</p>
<blockquote>
<p>在前端开发的过程中，我们经常会需要绑定一些持续触发的事件，如 resize、scroll、mousemove 等等，但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。 通常这种情况下防抖和节流是比较好的解决方案。</p>
<ul>
<li>防抖（debounce）: 所谓防抖，就是指触发事件后在 n 秒内函数只能执行一次，如果在 n 秒内又触发了事件，则会重新计算函数执行时间。</li>
</ul>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token comment" spellcheck="true">/**
  * @desc 函数防抖
  * @param func 函数
  * @param wait 延迟执行毫秒数
  * @param immediate true 表立即执行，false 表非立即执行
  */</span>
  <span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span>func<span class="token punctuation">,</span> wait<span class="token punctuation">,</span> immediate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> timeout<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> context <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
      <span class="token keyword">let</span> args <span class="token operator">=</span> arguments<span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>timeout<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timeout<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>immediate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">var</span> callNow <span class="token operator">=</span> <span class="token operator">!</span>timeout<span class="token punctuation">;</span>
        timeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span>
          timeout <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> wait<span class="token punctuation">)</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>callNow<span class="token punctuation">)</span> func<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> args<span class="token punctuation">)</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        timeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
          func<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> args<span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> wait<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<ul>
<li>节流（throttle）: 所谓节流，就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。</li>
</ul>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token comment" spellcheck="true">/**
  * @desc 函数节流
  * @param func 函数
  * @param wait 延迟执行毫秒数
  * @param type 1 表时间戳版，2 表定时器版
  */</span>
  <span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span>func<span class="token punctuation">,</span> wait <span class="token punctuation">,</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> previous <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>type<span class="token operator">===</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> timeout<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> context <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
      <span class="token keyword">let</span> args <span class="token operator">=</span> arguments<span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> now <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>now <span class="token operator">-</span> previous <span class="token operator">></span> wait<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            func<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
            previous <span class="token operator">=</span> now<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>timeout<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          timeout <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span>
            timeout <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
            func<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> args<span class="token punctuation">)</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span> wait<span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<p>参考文章：<a href="https://www.jianshu.com/p/c8b86b09daf0" target="_blank" rel="noopener">函数防抖和节流</a></p>
</blockquote>
</li>
</ul>
<ul>
<li><p>13.Dom 的<strong>重绘</strong>和<strong>回流</strong>呢？</p>
<blockquote>
<ul>
<li><strong>重绘（repaint）</strong>: （盒子模型的宽高、位置、样式确定后）浏览器把元素绘制出来称为重绘。当前元素的样式(背景颜色、字体颜色等)发生改变的时候，我们只需要把改变的元素重新的渲染一下即可 ,重绘对浏览器的性能影响较小，所以一般不考虑。</li>
<li><strong>回流（reflow）</strong>: 当页面上的结构发生改变，浏览器会从新的渲染我们的页面，回流是比较消耗性能的。<ul>
<li>回流产生的情况 <ul>
<li>1、添加或者删除可见的DOM元素； </li>
<li>2、元素位置改变； </li>
<li>3、元素尺寸改变——边距、填充、边框、宽度和高度 </li>
<li>4、内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变； </li>
<li>5、页面渲染初始化； </li>
<li>6、浏览器窗口尺寸改变——resize事件发生时；<br>由于回流 对浏览器的影响比较大，所以我们一般是用文档碎片的方式去解决这个问题的，当我们需要给DOM中添加新的元素的时候，先将其放在一个容器中，然后统一添加，这样就只产生了一次回流。</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token keyword">var</span> frg <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createDocumentFragment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment" spellcheck="true">// 创建了一个文档碎片:相当于一个容器，</span>
    <span class="token comment" spellcheck="true">// 把动态创建的li先放到容器中,最后一起添加到页面中(只引发一次回流)</span>
   <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">10</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
     <span class="token keyword">var</span> oLi <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"li"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     oLi<span class="token punctuation">.</span>onmouseover <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">"#22b909"</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span>
     oLi<span class="token punctuation">.</span>onmouseout <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
         <span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span>
     frg<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>oLi<span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   oUl<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>frg<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
</li>
<li><p>14.<code>Promise.all()</code> 和 <code>Promise.race()</code> 的优缺点有哪些？</p>
<blockquote>
<ul>
<li><p>Promise.all()</p>
<ul>
<li>常见使用场景 ： 多个异步结果合并到一起, Promise.all可以将多个Promise实例包装成一个新的Promise实例。用于将多个Promise实例，包装成一个新的Promise实例。</li>
<li>它接受一个可迭代对象，如 Array 或 String。</li>
<li>如果传入的参数是一个空的可迭代对象，则返回一个已完成（already resolved）状态的 Promise。</li>
<li>如果传入的参数不包含任何 promise，则返回一个异步完成（asynchronously resolved） Promise。注意：Google Chrome 58 在这种情况下返回一个已完成（already resolved）状态的 Promise。</li>
<li>其它情况下返回一个处理中（pending）的Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。</li>
<li>返回值将会按照参数内的 promise 顺序排列，而不是由调用 promise 的完成顺序决定。</li>
<li>此方法在集合多个 promise 的返回结果时很有用。</li>
<li>传入的数组可以是Promise对象，也可以是其它值，只有Promise会等待状态改变。</li>
<li>当所有的子Promise都完成，该Promise完成，返回值是全部值的数组。</li>
<li>如果有任何一个失败，该Promise失败，返回值是第一个失败的子Promise的结果。</li>
<li>在任何情况下，Promise.all 返回的 promise 的完成状态的结果都是一个数组，它包含所有的传入迭代参数对象的值（也包括非 promise 值）。</li>
<li>如果传入的 promise 中有一个失败（rejected），Promise.all 异步地将失败的那个结果给失败状态的回调函数，而不管其它 promise 是否完成。</li>
</ul>
</li>
<li><p><code>Promise.race()</code></p>
<ul>
<li>常见使用场景：把异步操作和定时器放到一起，如果定时器先触发，认为超时，告知用户</li>
<li>它接受一个可迭代对象，类似Array。</li>
<li>返回一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝，就采用第一个promise的值作为它的值，从而异步地解析或拒绝（一旦堆栈为空）。</li>
<li>race 函数返回一个 Promise，它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成（ resolves），也可以是失败（rejects），这要取决于第一个完成的方式是两个中的哪个。</li>
<li>如果传的迭代是空的，则返回的 promise 将永远等待。</li>
<li>如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺，则 Promise.race 将解析为迭代中找到的第一个值。</li>
<li>类似于Promise.all(), 区别在于<strong>它有任意一个返回成功后，就算完成，但是进程不会立即停止</strong></li>
</ul>
</li>
</ul>
</blockquote>
</li>
<li><p>15.<code>async/await</code> 与 <code>Promise</code> 的优缺点有哪些？</p>
<blockquote>
<p>async/await 是写异步代码的一种方式，以前的方法有回调函数和Promise。<br>async/await 是基于 Promise 实现的，它不能用于普通的回调函数。<br>async/await 与 Promise 一样，是非阻塞的。<br>async/await 使得异步代码看起来像同步代码。<br>await 关键字只能用在 async 定义的函数内。<br>async 函数会隐式地返回一个 Promise，该 Promise 的 resolve 值就是函数 return的值。</p>
<ul>
<li>async/await 相对于 Promise 的优点<ul>
<li>1.简洁: 不需要写.then，不需要写匿名函数处理Promise的resolve值，也不需要定义多余的data变量，还避免了嵌套代码。</li>
<li>2.错误处理: Promise中， try/catch 不能处理 Promise 中的错误，需要使用 .catch，使用 aync/await 的话，try/catch能处理Promise 中的错误:</li>
<li>3.可读性：async/await 编写可以大大地提高可读性。</li>
<li>4.错误栈: Promise 链中返回的错误栈不会准确的给出错误发生位置的线索, async/await 中的错误栈会指向错误所在的函数。</li>
</ul>
</li>
</ul>
</blockquote>
</li>
<li><p>16.Vue 的子组件中可以修改 props 的值吗？如果修改了会报错吗？</p>
<blockquote>
<p>先上张图，看看 Vue.js 作者的看法</p>
</blockquote>
<div style="width:100%;display:flex;flex-direction:column;justify-content:center;text-align:center;">

  <img src="https://pub.wangxuefeng.com.cn/asset/blogthumbnail/baiduInterview/modifyProps.png" style="width:100%;max-width:600px;margin: 5px auto;">

</div>

<blockquote>
<p>显然，作者都不希望在子组件中去修改父组件中的数据。</p>
<p>Vue.js 官网的描述如下：</p>
<p>所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定：父级 prop 的更新会向下流动到子组件中，但是反过来则不行。这样会防止从子组件意外改变父级组件的状态，从而导致你的应用的数据流向难以理解。<br>这里有两种常见的试图改变一个 prop 的情形：</p>
<p>这个 prop 用来传递一个初始值；这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下，最好定义一个本地的 data 属性并将这个 prop 用作其初始值：</p>
</blockquote>
<pre class=" language-js"><code class="language-js">  props<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'initialCounter'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  data<span class="token punctuation">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      counter<span class="token punctuation">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>initialCounter
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<p>这个 prop 以一种原始的值传入且需要进行转换。在这种情况下，最好使用这个 prop 的值来定义一个计算属性：</p>
</blockquote>
<pre class=" language-js"><code class="language-js">  props<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">'size'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  computed<span class="token punctuation">:</span> <span class="token punctuation">{</span>
    normalizedSize<span class="token punctuation">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>size<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<p>注意在 JavaScript 中对象和数组是通过引用传入的，所以对于一个数组或对象类型的 prop 来说，在子组件中改变这个对象或数组本身将会影响到父组件的状态。<br>额外的，每次父级组件发生更新时，子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了，Vue 会在浏览器的控制台中发出警告。<br>至于是否报错</p>
<ul>
<li>如果在子组件只是修改 prop 的<code>值</code>的话<ul>
<li>只有 prop 为非引用类型数据，譬如字符串，数字等，才会报错。</li>
<li>而对于引用类型的数据，如对象，数组等，不会报错。个人认为其原因可能是只是修改了其内部的值，其指针的指向性并没有发生改变。</li>
</ul>
</li>
<li>如果在子组件修改 prop 数组、对象的指针指向<ul>
<li>会报错</li>
</ul>
</li>
</ul>
<code style="color:red;">
  [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
</code>
</blockquote>
</li>
<li><p>17.手写一下深拷贝的代码吧。</p>
<blockquote>
<p>MDN 上的<code>取巧</code>写法</p>
</blockquote>
<pre class=" language-js"><code class="language-js">  <span class="token keyword">const</span> deepClone <span class="token operator">=</span> <span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> JSON<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>JSON<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<blockquote>
<p>这种写法如果出现循环引用的话，<code>JSON.stringify(obj)</code> 会抛出异常，而且不能够识别Function，因此这种写法适用于一些比较简单无循环引用、无Function的对象深拷贝</p>
<p>经过琢磨，自己写了一个深拷贝的类，感觉要解决循环引用问题，只用一个方法还是有点困难的，所以通过类里的多个方法和属性协同解决。代码如下：</p>
</blockquote>
<pre class=" language-js"><code class="language-js"><span class="token comment" spellcheck="true">// 原创代码，只此一家，如有雷同，纯属巧合</span>

  <span class="token keyword">class</span> <span class="token class-name">DeepClone</span> <span class="token punctuation">{</span>
    <span class="token function">constructor</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>src <span class="token operator">=</span> obj <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// 要拷贝的对象</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>hasClonedObj <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// 缓存 已经拷贝过的 object</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>_Circular_reference_tag <span class="token operator">=</span> <span class="token string">'$ref'</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// 循环引用占位符</span>
    <span class="token punctuation">}</span>
    <span class="token function">reset</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// 清空已经拷贝过的 object</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>hasClonedObj <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token function">finishedCloneObj</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// 暂存已经拷贝过的 object， 用于判断是否循环引用</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>hasClonedObj<span class="token punctuation">.</span><span class="token function">every</span><span class="token punctuation">(</span>e <span class="token operator">=</span><span class="token operator">></span> e <span class="token operator">!==</span> obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>hasClonedObj<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token function">hasObjClone</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// 判断 obj 是否已经拷贝过，即判断是否有循环引用</span>
      <span class="token keyword">let</span> rs <span class="token operator">=</span> <span class="token punctuation">{</span> hasClone<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> index<span class="token punctuation">:</span> <span class="token keyword">null</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>hasClonedObj<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">===</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          rs <span class="token operator">=</span> <span class="token punctuation">{</span> hasClone<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> index<span class="token punctuation">:</span> i <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> rs<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token function">deepClone</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// 清空缓存    </span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">deepCloneCore</span><span class="token punctuation">(</span>src <span class="token operator">||</span> <span class="token keyword">this</span><span class="token punctuation">.</span>src<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// 深度拷贝</span>
    <span class="token punctuation">}</span>
    <span class="token function">cloneAndParseCR</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">reset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// 清空缓存    </span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parseCircularReference</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">deepCloneCore</span><span class="token punctuation">(</span>src <span class="token operator">||</span> <span class="token keyword">this</span><span class="token punctuation">.</span>src<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment" spellcheck="true">// “深”度拷贝 还原循环引用</span>
    <span class="token punctuation">}</span>
    <span class="token function">parseCircularReference</span><span class="token punctuation">(</span>rsObj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// 解析循环引用，还原占位符</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> rsObj <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>rsObj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          rsObj<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>e <span class="token operator">=</span><span class="token operator">></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parseCircularReference</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token comment" spellcheck="true">// 递归深解析循环引用</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>rsObj <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
          <span class="token comment" spellcheck="true">// 如果时 null，直接返回 null</span>
          Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>rsObj<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>key <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>rsObj<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
              rsObj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">parseCircularReference</span><span class="token punctuation">(</span>rsObj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> rsObj <span class="token operator">===</span> <span class="token string">'string'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>rsObj<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>_Circular_reference_tag<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
          <span class="token keyword">let</span> crObj <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>hasClonedObj<span class="token punctuation">[</span><span class="token function">Number</span><span class="token punctuation">(</span>rsObj<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex">/[0-9]+/</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          rsObj <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>crObj<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token punctuation">[</span><span class="token operator">...</span>crObj<span class="token punctuation">]</span> <span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token operator">...</span>crObj<span class="token punctuation">}</span><span class="token punctuation">;</span>
          <span class="token comment" spellcheck="true">// 还原占位符， 此处为深度为一的"深"拷贝，本质为浅拷贝</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> rsObj<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token function">deepCloneCore</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> target<span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> src <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">let</span> <span class="token punctuation">{</span> hasClone<span class="token punctuation">,</span> index <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasObjClone</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>hasClone<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token comment" spellcheck="true">// 如果循环引用</span>
          <span class="token keyword">return</span> <span class="token template-string"><span class="token string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>_Circular_reference_tag<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>index<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span>
          <span class="token comment" spellcheck="true">// 返回占位符与下标组成的字符串</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>src<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">finishedCloneObj</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token comment" spellcheck="true">// 缓存已经拷贝过的对象</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          target <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          src<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span>e<span class="token punctuation">,</span> i<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">></span> target<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">deepCloneCore</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token comment" spellcheck="true">// 递归深度拷贝数组</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>src <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
          <span class="token comment" spellcheck="true">// 如果时 null，直接返回 null</span>
          target <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
          Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>src<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>key <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">{</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>src<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
              target<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">deepCloneCore</span><span class="token punctuation">(</span>src<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>
          <span class="token comment" spellcheck="true">// 循环递归深度拷贝对象</span>
        <span class="token punctuation">}</span> 
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>        
        target <span class="token operator">=</span> src
        <span class="token comment" spellcheck="true">// 非 object 类型直接赋值拷贝</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> target
      <span class="token comment" spellcheck="true">// 返回拷贝结果</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span></code></pre>
<blockquote>
<p>其实 17题 是由 16题 而来的，面试官提问的顺序极其有逻辑，如果你还不太清楚 16题 和 17题 有啥关系，那么可以<code>康康</code>这篇文章<a href="https://www.cnblogs.com/hutuzhu/p/10119698.html" target="_blank" rel="noopener">在vue中子组件修改props引发的对js深拷贝和浅拷贝的思考</a>;</p>
</blockquote>
</li>
</ul>
<p>感谢你能看到这里！本人能力有限，本文中可能有些纰漏或者不正确之处，还请批评指正。<br><br><br>以上！</p>

        
                <blockquote style="margin: 2em 0 0;padding: 0.5em 1em;border-left: 3px solid #F44336;background-color: #F5F5F5;list-style: none;">
                    <p><strong>
                         
                            本博客遵循<a href="https://creativecommons.org/licenses/by-nc-sa/3.0/cn/" target="_blank">署名-非商业性使用-相同方式共享 3.0 中国大陆 (CC BY-NC-SA 3.0 CN)</a>协议
                        </strong>
                        <br>
                        <strong>本文链接：</strong><a href="https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html">https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html</a>
                    </p>
                </blockquote>
        
    

    
</div>


                <!-- Post Feeding -->
                
                    <style type="text/css">
  .post-feeding,
  .post-feeding-warp {
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .post-feeding {
    flex-direction: column;
  }
  .post-feeding-item {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    margin: 5px 10px;
  }
  .post-feeding-text {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
  }
  .post-feeding-text span {
    color: rgb(102, 165, 228);
    text-align: center;
  }
  .post-feeding-text-content {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
  }
</style>
<div class="post-feeding">
  
    <div class="post-feeding-text">
      <span>(●'◡'●)</span>
      <div class="post-feeding-text-content">
        <span>如果你觉得不错或者对你有帮助， </span>
        <span>你可以替我买一杯咖啡 ☕</span>
      </div>
      <div class="post-feeding-text-content">
        <span>If you think it's good or helpful,&nbsp;&nbsp;</span>
        <span>you can buy me a cup of coffee ☕</span>
      </div>
    </div>
    <div class="post-feeding-warp">
      
        <div class="post-feeding-item">
          <img src="https://pub.wangxuefeng.com.cn/feed/qrcode_onlyqr_feedme_ailpay.png" alt="buy me a coffce via ailpay" title="Buy me a coffce via Ailpay" width="100">
          <span>Ailpay</span>
        </div>
      
      
        <div class="post-feeding-item">
          <img src="https://pub.wangxuefeng.com.cn/feed/qrcode_onlyqr_feedme_wechat.png" alt="buy me a coffce via wechat" title="Buy me a coffce via Wechat" width="100">
          <span>Wechat</span>
        </div>
      
    </div>
  
</div>
                

                

                <!-- Post Comments -->
                
                    
    <!-- 使用 DISQUS_CLICK -->
<div id="disqus-comment">
    <div id="disqus_thread"></div>

<!-- add animation -->
<style>
	.disqus_click_btn {
            line-height: 30px;
            margin: 0;
            min-width: 50px;
            padding: 0 14px;
            display: inline-block;
            font-family: "Roboto", "Helvetica", "Arial", sans-serif;
            font-size: 14px;
            font-weight: 400;
            text-transform: uppercase;
            letter-spacing: 0;
            overflow: hidden;
            will-change: box-shadow;
            transition: box-shadow .2s cubic-bezier(.4, 0, 1, 1), background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1);
            outline: 0;
            cursor: pointer;
            text-decoration: none;
            text-align: center;
            vertical-align: middle;
            border: 0;
            background: rgba(158, 158, 158, .2);
            box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
            color: #fff;
            background-color: #757575;
            text-shadow: 0;
            display: none
        }
</style>
	
<div class="btn_click_load"> 
    <button class="disqus_click_btn">阅读评论（请确保 disqus 可以正常加载）</button>
</div>

<script type="text/javascript">
    var disqus_config = function () {
        this.page.url = 'https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html';  // Replace PAGE_URL with your page's canonical URL variable
        this.page.identifier = 'https://blog.wangxuefeng.com.cn/archives/Baidu-FE-interview.html'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
    };
</script>

<script type="text/ls-javascript" id="disqus-lazy-load-script">
    $.ajax({
        url: 'https://disqus.com/next/config.json',
        timeout: 4000,
        type: 'GET',
        success: (function() {
            var d = document;
            var s = d.createElement('script');
            s.src = '//xuefeng.disqus.com/embed.js';
            s.setAttribute('data-timestamp', + new Date());
            (d.head || d.body).appendChild(s);
            $('.disqus_click_btn').css('display','none');
        })(),
        error: function() {
          $('.disqus_click_btn').css('display','block');
        }
    });
    $('.btn_click_load').click(function() {  //click to load comments
        (function() { // DON'T EDIT BELOW THIS LINE
            var d = document;
            var s = d.createElement('script');
            s.src = '//xuefeng.disqus.com/embed.js';
            s.setAttribute('data-timestamp', + new Date());
            (d.head || d.body).appendChild(s);
        })();
        $('.disqus_click_btn').css('display','none');
    });
</script>
  	

</div>
<style>
    #disqus-comment{
        background-color: #eee;
        padding: 2pc;
    }
</style>

                
            </div>

            <!-- Post Prev & Next Nav -->
            <nav class="material-nav mdl-color-text--grey-50 mdl-cell mdl-cell--12-col">
    <!-- Prev Nav -->
    
        <a href="/archives/2019self-summary.html" id="post_nav-newer" class="prev-content">
            <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-color--white mdl-color-text--grey-900" role="presentation">
                <i class="material-icons">arrow_back</i>
            </button>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            新篇
        </a>
    

    <!-- Section Spacer -->
    <div class="section-spacer"></div>

    <!-- Next Nav -->
    
        <a href="/archives/graduation.html" id="post_nav-older" class="next-content">
            旧篇
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-color--white mdl-color-text--grey-900" role="presentation">
                <i class="material-icons">arrow_forward</i>
            </button>
        </a>
    
</nav>

        </div>
    </div>



                    
                        <!-- Overlay For Active Sidebar -->
<div class="sidebar-overlay"></div>

<!-- Material sidebar -->
<aside id="sidebar" class="sidebar sidebar-colored sidebar-fixed-left" role="navigation">
    <div id="sidebar-main">
        <!-- Sidebar Header -->
        <div class="sidebar-header header-cover" style="background-image: url(/img/sidebar_header.png);">
    <!-- Top bar -->
    <div class="top-bar"></div>

    <!-- Sidebar toggle button -->
    <button type="button" class="sidebar-toggle mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon" style="display: initial;" data-upgraded=",MaterialButton,MaterialRipple">
        <i class="material-icons">clear_all</i>
        <span class="mdl-button__ripple-container">
            <span class="mdl-ripple">
            </span>
        </span>
    </button>

    <!-- Sidebar Avatar -->
    <div class="sidebar-image">
        <img src="https://pub.wangxuefeng.com.cn/asset/defaultHead/avatar.png" alt="w-xuefeng's avatar">
    </div>

    <!-- Sidebar Email -->
    <a data-toggle="dropdown" class="sidebar-brand" href="#settings-dropdown">
        xuefeng@wangxuefeng.com.cn
        <b class="caret"></b>
    </a>
</div>


        <!-- Sidebar Navigation  -->
        <ul class="nav sidebar-nav">
    <!-- User dropdown  -->
    <li class="dropdown">
        <ul id="settings-dropdown" class="dropdown-menu">
            
                <li>
                    <a href="https://www.wangxuefeng.com.cn" target="_blank" title="XueFeng&#39;s Home">
                        
                            <i class="material-icons sidebar-material-icons sidebar-indent-left1pc-element">person</i>
                        
                        XueFeng&#39;s Home
                    </a>
                </li>
            
                <li>
                    <a href="mailto: xuefeng@wangxuefeng.com.cn" target="_blank" title="Email Me">
                        
                            <i class="material-icons sidebar-material-icons sidebar-indent-left1pc-element">email</i>
                        
                        Email Me
                    </a>
                </li>
            
        </ul>
    </li>

    <!-- Homepage -->
    
        <li id="sidebar-first-li">
            <a href="/">
                
                    <i class="material-icons sidebar-material-icons">home</i>
                
                主页
            </a>
        </li>
        
    

    <!-- Archives  -->
    
        <li class="dropdown">
            <a href="#" class="ripple-effect dropdown-toggle" data-toggle="dropdown">
                
                    <i class="material-icons sidebar-material-icons">inbox</i>
                
                    归档
                <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
            <li>
                <a class="sidebar_archives-link" href="/archives/2020/05/">五月 2020<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2020/03/">三月 2020<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2020/01/">一月 2020<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/08/">八月 2019<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/06/">六月 2019<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/05/">五月 2019<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/12/">十二月 2018<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/08/">八月 2018<span class="sidebar_archives-count">5</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/07/">七月 2018<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/04/">四月 2018<span class="sidebar_archives-count">2</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/03/">三月 2018<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/12/">十二月 2017<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/11/">十一月 2017<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/06/">六月 2017<span class="sidebar_archives-count">1</span></a>
            </ul>
        </li>
        
    

    <!-- Categories  -->
    
        <li class="dropdown">
            <a href="#" class="ripple-effect dropdown-toggle" data-toggle="dropdown">
                
                    <i class="material-icons sidebar-material-icons">chrome_reader_mode</i>
                
                分类
                <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
                <li>
                <a class="sidebar_archives-link" href="/categories/SU%E5%B0%94%E4%B8%8D%E8%AE%A4%E8%BE%93-%E4%BA%A7%E5%93%81%E7%AF%87/">SU尔不认输 | 产品篇<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/SU%E5%B0%94%E4%B8%8D%E8%AE%A4%E8%BE%93-%E8%AF%BB%E4%B9%A6%E4%BC%9A/">SU尔不认输 | 读书会<span class="sidebar_archives-count">4</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF%E8%B4%B4-iOS-%E5%BC%80%E5%8F%91/">技术贴 | iOS 开发<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF%E8%B4%B4-%E6%80%BB%E7%BB%93%E7%B1%BB/">技术贴 | 总结类<span class="sidebar_archives-count">2</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF%E8%B4%B4-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/">技术贴 | 数据结构<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF%E8%B4%B4-%E7%AE%97%E6%B3%95%E7%B1%BB/">技术贴 | 算法类<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E6%8A%80%E6%9C%AF%E8%B4%B4-%E9%9D%A2%E8%AF%95%E9%A2%98/">技术贴 | 面试题<span class="sidebar_archives-count">3</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E6%B5%81%E6%B0%B4%E8%B4%A6-%E6%80%BB%E7%BB%93%E7%B1%BB/">流水账 | 总结类<span class="sidebar_archives-count">3</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E7%94%9F%E6%B4%BB%E7%BA%AA%E5%AE%9E-%E8%A7%86%E9%A2%91%E7%B1%BB/">生活纪实 | 视频类<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E7%9F%A5%E8%AF%86%E5%88%86%E4%BA%AB-%E8%A7%86%E9%A2%91%E7%B1%BB/">知识分享 | 视频类<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/%E9%98%B3%E5%85%89%E7%BD%91%E7%AB%99-%E4%B8%80%E5%B0%81%E4%BF%A1/">阳光网站  | 一封信<span class="sidebar_archives-count">1</span></a>
            </ul>
        </li>
        
            <li class="divider"></li>
        
    

    <!-- Pages  -->
    
        <li>
            <a href="/tags" title="标签云">
                
                    <i class="material-icons sidebar-material-icons">loyalty</i>
                
                标签云
            </a>
        </li>
        
    
        <li>
            <a href="/timeline" title="时光之轴">
                
                    <i class="material-icons sidebar-material-icons">access_time</i>
                
                时光之轴
            </a>
        </li>
        
    
        <li>
            <a href="/links" title="友情链接">
                
                    <i class="material-icons sidebar-material-icons">send</i>
                
                友情链接
            </a>
        </li>
        
    
        <li>
            <a href="/about" title="关于我">
                
                    <i class="material-icons sidebar-material-icons">person</i>
                
                关于我
            </a>
        </li>
        
    

    <!-- Article Number  -->
    
</ul>


        <!-- Sidebar Footer -->
        <!--
I'm glad you use this theme, the development is no so easy, I hope you can keep the copyright, I will thank you so much.
If you still want to delete the copyrights, could you still retain the first one? Which namely "Theme Material"
It will not impact the appearance and can give developers a lot of support :)

很高兴您使用并喜欢该主题，开发不易 十分谢谢与希望您可以保留一下版权声明。
如果您仍然想删除的话 能否只保留第一项呢？即 "Theme Material"
它不会影响美观并可以给开发者很大的支持和动力。 :)
-->

<!-- Sidebar Divider -->

    <div class="sidebar-divider"></div>


<!-- Theme Material -->

    <a href="https://github.com/viosey/hexo-theme-material"  class="sidebar-footer-text-a" target="_blank">
        <div class="sidebar-text mdl-button mdl-js-button mdl-js-ripple-effect sidebar-footer-text-div" data-upgraded=",MaterialButton,MaterialRipple">
            主题 - Material
            <span class="sidebar-badge badge-circle">i</span>
        </div>
    </a>


<!-- Help & Support -->
<!--

-->

<!-- Feedback -->
<!--

-->

<!-- About Theme -->
<!--

-->

    </div>

    <!-- Sidebar Image -->
    

</aside>

                    

                    
                        <!-- Footer Top Button -->
                        <div id="back-to-top" class="toTop-wrap">
    <a href="#top" class="toTop">
        <i class="material-icons footer_top-i">expand_less</i>
    </a>
</div>

                    

                    <!--Footer-->
<footer class="mdl-mini-footer" id="bottom">
    
        <!-- Paradox Footer Left Section -->
        <div class="mdl-mini-footer--left-section sns-list">
    <!-- Twitter -->
    
        <a href="https://twitter.com/XueFeng_W" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-twitter">
                <span class="visuallyhidden">Twitter</span>
            </button><!--
     --></a>
    

    <!-- Facebook -->
    

    <!-- Google + -->
    
        <a href="https://plus.google.com/103648995569548189496" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-gplus">
                <span class="visuallyhidden">Google Plus</span>
            </button><!--
     --></a>
    

    <!-- Weibo -->
    
        <a href="https://weibo.com/feuxw" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-weibo">
                <span class="visuallyhidden">Weibo</span>
            </button><!--
     --></a>
    

    <!-- Instagram -->
    

    <!-- Tumblr -->
    

    <!-- Github -->
    
        <a href="https://github.com/w-xuefeng/" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-github">
                <span class="visuallyhidden">Github</span>
            </button><!--
     --></a>
    

    <!-- LinkedIn -->
    

    <!-- Zhihu -->
    
        <a href="https://www.zhihu.com/people/xue-feng-30-55/activities" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-zhihu">
                <span class="visuallyhidden">Zhihu</span>
            </button><!--
     --></a>
    

    <!-- Bilibili -->
    

    <!-- Telegram -->
    

    <!-- V2EX -->
    

    <!-- Segmentfault -->
    
</div>


        <!--Copyright-->
        <div id="copyright">
            Copyright&nbsp;©&nbsp;<span year></span>&nbsp;boXue·Fengke
            
                <br>
                
                    <a href="http://beian.miit.gov.cn" target="_blank" rel="nofollow noopener" style="text-decoration: none;color: #9e9e9e;">陇ICP备16002668号-1</a><!-- Hotjar Tracking Code for blog.wangxuefeng.com.cn --> <script> (function(h,o,t,j,a,r){ h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; h._hjSettings={hjid:1050089,hjsv:6}; a=o.getElementsByTagName("head")[0]; r=o.createElement("script");r.async=1; r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; a.appendChild(r); })(window,document,"https://static.hotjar.com/c/hotjar-",".js?sv="); </script>
                
            
        </div>

        <!-- Paradox Footer Right Section -->

        <!--
        I am glad you use this theme, the development is no so easy, I hope you can keep the copyright.
        It will not impact the appearance and can give developers a lot of support :)

        很高兴您使用该主题，开发不易，希望您可以保留一下版权声明。
        它不会影响美观并可以给开发者很大的支持。 :)
        -->

        <div class="mdl-mini-footer--right-section">
            <div>
                <div class="footer-develop-div">Powered by <a href="https://hexo.io" target="_blank" class="footer-develop-a">Hexo</a></div>
                <div class="footer-develop-div">Theme - <a href="https://github.com/viosey/hexo-theme-material" target="_blank" class="footer-develop-a">Material</a></div>
            </div>
        </div>
    
</footer>


                    <!-- Import JS File -->

    <script>lsloader.load("lazyload_js","/js/lazyload.min.js?1BcfzuNXqV+ntF6gq+5X3Q==", true)</script>



    <script>lsloader.load("js_js","/js/js.min.js?Bn9UzEm8RrBSxqyZB0zPjA==", true)</script>



    <script>lsloader.load("np_js","/js/nprogress.js?pl3Qhb9lvqR1FlyLUna1Yw==", true)</script>


<script type="text/ls-javascript" id="NProgress-script">
    NProgress.configure({
        showSpinner: true
    });
    NProgress.start();
    $('#nprogress .bar').css({
        'background': '#29d'
    });
    $('#nprogress .peg').css({
        'box-shadow': '0 0 10px #29d, 0 0 15px #29d'
    });
    $('#nprogress .spinner-icon').css({
        'border-top-color': '#29d',
        'border-left-color': '#29d'
    });
    setTimeout(function() {
        NProgress.done();
        $('.fade').removeClass('out');
    }, 800);
</script>









   <!-- 使用 DISQUS js 代码 -->






<!-- UC Browser Compatible -->
<script>
	var agent = navigator.userAgent.toLowerCase();
	if(agent.indexOf('ucbrowser')>0) {
		document.write('<link rel="stylesheet" href="/css/uc.css">');
	   alert('由于 UC 浏览器使用极旧的内核，而本网站使用了一些新的特性。\n为了您能更好的浏览，推荐使用 Chrome 或 Firefox 浏览器。');
	}
</script>

<!-- Import prettify js  -->



<!-- Window Load -->
<!-- add class for prettify -->
<script type="text/ls-javascript" id="window-load">
    $(window).on('load', function() {
        // Post_Toc parent position fixed
        $('.post-toc-wrap').parent('.mdl-menu__container').css('position', 'fixed');
    });

    
    
</script>

<!-- MathJax Load-->


<!-- Bing Background -->


<script type="text/ls-javascript" id="lazy-load">
    // Offer LazyLoad
    queue.offer(function(){
        $('.lazy').lazyload({
            effect : 'show'
        });
    });

    // Start Queue
    $(document).ready(function(){
        setInterval(function(){
            queue.execNext();
        },200);
    });
</script>

<!-- Custom Footer -->



<script>
    var copyrightNow = new Date().getFullYear();
    var textContent = document.querySelector('span[year]')

    copyrightSince = 0000;
    if (copyrightSince === copyrightNow||copyrightSince === 0000) {
        textContent.textContent = copyrightNow
    } else {
        textContent.textContent = copyrightSince + ' - ' + copyrightNow
    }

    (function(){
        var scriptList = document.querySelectorAll('script[type="text/ls-javascript"]')

        for (var i = 0; i < scriptList.length; ++i) {
            var item = scriptList[i];
            lsloader.runInlineScript(item.id,item.id);
        }
    })()
console.log('\n %c © Material Theme | Version: 1.5.6 | https://github.com/viosey/hexo-theme-material %c \n', 'color:#455a64;background:#e0e0e0;padding:5px 0;border-top-left-radius:5px;border-bottom-left-radius:5px;', 'color:#455a64;background:#e0e0e0;padding:5px 0;border-top-right-radius:5px;border-bottom-right-radius:5px;');
</script>

                </main>
            </div><!-- hexo-inject:begin --><!-- hexo-inject:end -->
        </body>
    
</html>
